//package thesis.servlets;
package thesis.javaclass;

import thesis.database.*;

import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Scanner;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathExpressionException;

import org.springframework.dao.DataAccessException;
import org.xml.sax.SAXException;

public class SystemModel {
	private static String server = "localhost";
	private static int port = 30000;

	static {
		ConfirmServer s = new ConfirmServer();
		Thread confirmServerThread = new Thread(s, "Confirm server");
		confirmServerThread.start();
		TaxiFinderServer tFS = new TaxiFinderServer();
		Thread tFSThread = new Thread(tFS);
		tFSThread.start();
	}

	public static boolean addCustomer(Customer customer) {

		try {
			CustomerJDBCTemplate cusTem = (CustomerJDBCTemplate) Factory
					.createJDBCTemplate("customerJDBCTemplate");
			cusTem.create(customer);
		} catch (DataAccessException e) {
			e.printStackTrace();
			return false;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}

		return true;
	}

	public static boolean addTaxi(Taxi taxi) {
		try {
			TaxiJDBCTemplate taxiTem = (TaxiJDBCTemplate) Factory
					.createJDBCTemplate("taxiJDBCTemplate");
			taxiTem.create(taxi);
		} catch (DataAccessException dae) {
			dae.printStackTrace();
			return false;
		} catch (Exception e) {
			e.printStackTrace();
			return false;

		}
		return true;
	}

	public static Customer getCustomer(int customerId) {

		Customer customer = null;
		try {
			CustomerJDBCTemplate cusTem = (CustomerJDBCTemplate) Factory
					.createJDBCTemplate("customerJDBCTemplate");
			customer = cusTem.getCustomer(customerId);
		} catch (DataAccessException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return customer;
	}

	public static Customer getCustomerByPhoneNumber(String phoneNumber) {
		Customer customer = null;
		try {
			CustomerJDBCTemplate cusTem = (CustomerJDBCTemplate) Factory
					.createJDBCTemplate("customerJDBCTemplate");
			customer = cusTem.getCustomerByPhoneNumber(phoneNumber);
		} catch (DataAccessException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return customer;
	}

	public static List<Customer> getAllCustomers() {
		CustomerJDBCTemplate cusTem = (CustomerJDBCTemplate) Factory
				.createJDBCTemplate("customerJDBCTemplate");

		return cusTem.listCustomers();
	}

	public static boolean deleteCustomer(int customerId) {

		try {
			CustomerJDBCTemplate cusTem = (CustomerJDBCTemplate) Factory
					.createJDBCTemplate("customerJDBCTemplate");
			cusTem.delete(customerId);
		} catch (DataAccessException e) {
			e.printStackTrace();
			return false;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	public static Taxi getTaxi(int taxiId) {
		Taxi taxi = null;
		try {
			TaxiJDBCTemplate taxiTem = (TaxiJDBCTemplate) Factory
					.createJDBCTemplate("taxiJDBCTemplate");
			taxi = taxiTem.getTaxi(taxiId);
		} catch (DataAccessException dae) {
			dae.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return taxi;
	}

	public static List<Taxi> getTaxiByNumberPlate(String numberPlate) {
		List<Taxi> taxies = null;
		try {
			TaxiJDBCTemplate taxiTem = (TaxiJDBCTemplate) Factory
					.createJDBCTemplate("taxiJDBCTemplate");
			taxies = taxiTem.getTaxiesByNumber(numberPlate);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return taxies;
	}

	public static boolean deleteTaxi(int taxiId) {
		try {
			TaxiJDBCTemplate taxiTem = (TaxiJDBCTemplate) Factory
					.createJDBCTemplate("taxiJDBCTemplate");
			taxiTem.delete(taxiId);
		} catch (DataAccessException dae) {
			dae.printStackTrace();
			return false;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	public static boolean updateCustomer(Customer customer) {

		try {
			CustomerJDBCTemplate cusTem = (CustomerJDBCTemplate) Factory
					.createJDBCTemplate("customerJDBCTemplate");
			cusTem.update(customer);
		} catch (DataAccessException e) {
			e.printStackTrace();
			return false;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	public static boolean updateTaxi(Taxi taxi) {
		try {
			TaxiJDBCTemplate taxiTem = (TaxiJDBCTemplate) Factory
					.createJDBCTemplate("taxiJDBCTemplate");
			taxiTem.update(taxi);
		} catch (DataAccessException dae) {
			dae.printStackTrace();
			return false;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	public static User validate(String username, String password) {
		User user = null;
		try {
			UserJDBCTemplate userTem = (UserJDBCTemplate) Factory
					.createJDBCTemplate("userJDBCTemplate");
			user = userTem.getUserByUsername(username);
			if (user == null)
				return null;
			else if (!user.getPassword().equals(generateMD5(password.trim())))
				return null;
		} catch (DataAccessException dae) {
			dae.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return user;
		// goi methode trong DAO de kiem tra nguoi dung dang nhap
	}

	public static int getCustomerId(String phoneNumber) {
		CustomerJDBCTemplate customerTem = (CustomerJDBCTemplate) Factory
				.createJDBCTemplate("customerJDBCTemplate");
		Customer customer = customerTem.getCustomerByPhoneNumber(phoneNumber);
		if (customer != null)
			return customer.getCustomerId();
		return -1;
	}

	public static List<Customer> getCusBySearch(String phone) {
		CustomerJDBCTemplate customerTem = (CustomerJDBCTemplate) Factory
				.createJDBCTemplate("customerJDBCTemplate");

		return customerTem.getCusApproNumber(phone);
	}

	public static boolean addCustomer(String name, String address,
			String phoneNumber) {
		Customer customer = new Customer(-1, name, address, "", address,
				new Timestamp((new Date()).getTime()), new Timestamp(
						(new Date()).getTime()), phoneNumber, "", phoneNumber);
		return addCustomer(customer);
	}

	public static ArrayList<String> allAddress(int customerId) {
		CustomerJDBCTemplate customerTem = (CustomerJDBCTemplate) Factory
				.createJDBCTemplate("customerJDBCTemplate");
		return customerTem.getAddressesById(customerId);
	}

	public static boolean updateCustomer(int customerId, String address) {
		// Customer customer = new Customer(customerId, customerName,
		// homeAddress, officeAddress, lastestAddress, creationTime, lastUpdate,
		// homePhone, officePhone, newestPhone)
		return true;
	}

	public static List<Taxi> getAllTaxies() {
		TaxiJDBCTemplate taxiList = (TaxiJDBCTemplate) Factory
				.createJDBCTemplate("taxiJDBCTemplate");
		List<Taxi> taxies = taxiList.listTaxies();

		return taxies;
	}

	public static List<Route> getRouteById(int id, String start, String end) {
		RouteJDBCTemplate routeList = (RouteJDBCTemplate) Factory
				.createJDBCTemplate("routeJDBCTemplate");

		List<Route> routes = routeList.getRouteById(id, start, end);
		return routes;
	}

	public static List<Route> getRouteIn10Days(int id) {
		RouteJDBCTemplate routeList = (RouteJDBCTemplate) Factory
				.createJDBCTemplate("routeJDBCTemplate");

		List<Route> list = routeList.getRoutesIn10Days(id);
		return list;
	}

	public static Service getServiceById(int id) {
		ServiceJDBCTemplate ser = (ServiceJDBCTemplate) Factory
				.createJDBCTemplate("serviceJDBCTemplate");

		return ser.getService(id);
	}

	public static int createServiceReturnId(Service s) {
		ServiceJDBCTemplate ser = (ServiceJDBCTemplate) Factory
				.createJDBCTemplate("serviceJDBCTemplate");
		return ser.createReturnId(s);
	}

	public static int creatCustomerReturnId(Customer c) {
		CustomerJDBCTemplate cus = (CustomerJDBCTemplate) Factory
				.createJDBCTemplate("customerJDBCTemplate");

		return cus.createAndReturnId(c);
	}

	public static List<User> getAllUser() {
		UserJDBCTemplate user = (UserJDBCTemplate) Factory
				.createJDBCTemplate("userJDBCTemplate");

		return user.listUsers();
	}

	public static int addUser(User user) {
		UserJDBCTemplate u = (UserJDBCTemplate) Factory
				.createJDBCTemplate("userJDBCTemplate");

		return u.create(user);
	}

	public static User getUserById(int id) {
		UserJDBCTemplate u = (UserJDBCTemplate) Factory
				.createJDBCTemplate("userJDBCTemplate");

		return u.getUser(id);
	}

	public static int updateUser(User user) {
		UserJDBCTemplate u = (UserJDBCTemplate) Factory
				.createJDBCTemplate("userJDBCTemplate");

		return u.update(user);
	}

	public static User checkNameOfUserExist(String name) {
		try {
			UserJDBCTemplate u = (UserJDBCTemplate) Factory
					.createJDBCTemplate("userJDBCTemplate");

			return u.getUserByUsername(name);
		} catch (Exception e) {
			return null;
		}
	}

	public static int deleteUser(int id) {
		UserJDBCTemplate u = (UserJDBCTemplate) Factory
				.createJDBCTemplate("userJDBCTemplate");

		return u.delete(id);
	}

	public static List<User> getListUserByName(String name) {
		UserJDBCTemplate u = (UserJDBCTemplate) Factory
				.createJDBCTemplate("userJDBCTemplate");

		return u.getListUserByName(name);
	}

	public static ArrayList<String> findRelavantTaxi(
			ArrayList<TempAccept> acceptedTaxi, String address,
			int numberOfSeat, String phoneNumber) {

		ArrayList<Double> coordinate = null;
		try {
			coordinate = MapFunction.getCoordinate(address);
		} catch (XPathExpressionException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}

		if (coordinate == null) {
			return new ArrayList<String>(); // not found coordinate form address
		}

		ServiceRequest serviceRequest = new ServiceRequest(acceptedTaxi);
		serviceRequest.setAddress(address);
		serviceRequest.setNumberOfSeat(numberOfSeat);
		serviceRequest.setCoordinate(coordinate);
		serviceRequest.setPhoneNumber(phoneNumber);

		// comunicate with server
		try {
			Socket socket = new Socket(server, port);
			Scanner input = new Scanner(socket.getInputStream());
			PrintWriter output = new PrintWriter(socket.getOutputStream(), true);
			String inMessage = "";
			String outMessage = phoneNumber + ";" + address + ";"
					+ coordinate.get(0) + ";" + coordinate.get(1) + ";"
					+ String.valueOf(numberOfSeat);
			output.println(outMessage);
			System.out.println("Sent success...");
			while (true) {
				inMessage = input.nextLine();
				System.out.println(inMessage);
				String[] data = inMessage.split(",");
				String imei = data[0];
				if (data[0].equals("0")) {
					acceptedTaxi.clear();
					serviceRequest.getAcceptTaxiImeis().clear();
				} else if (data[1].equals("1")) {
					serviceRequest.setSelectedImei(imei);
					break;
				} else {
					serviceRequest.getAcceptTaxiImeis().add(data[0]);
					TaxiJDBCTemplate taxiJDBC = (TaxiJDBCTemplate) Factory
							.createJDBCTemplate("taxiJDBCTemplate");
					String numberPlate = taxiJDBC.getNumberPlateByImei(imei);
					serviceRequest.addAcceptedTaxiNumber(numberPlate);
				}
			}

		} catch (UnknownHostException e) {
			System.out.println("Invalid host");
		} catch (IOException e) {
			System.out.println("Can not connect port " + port);
		}

		// ///////////////////////////////
		while (serviceRequest.getSelectedImei().equals("")) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		// System.out.println("acceptTaxiId: " + Singleton.getAcceptaxiId());
		TaxiJDBCTemplate taxiTem = (TaxiJDBCTemplate) Factory
				.createJDBCTemplate("taxiJDBCTemplate");

		ArrayList<String> acceptedTaxies = new ArrayList<String>();
		for (String imei : serviceRequest.getAcceptTaxiImeis())
			acceptedTaxies.add(taxiTem.getNumberPlateByImei(imei));

		return acceptedTaxies;
	}

	private static String generateMD5(String str) {
		try {
			MessageDigest m = MessageDigest.getInstance("MD5");
			m.update(str.getBytes(), 0, str.length());
			return new BigInteger(1, m.digest()).toString(16);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return null;
	}

}
